package org.jvm.nativemethod.methods.sun.reflect;

import org.jvm.instruction.base.InstructionUtil;
import org.jvm.nativemethod.*;
import org.jvm.rtda.Object;
import org.jvm.rtda.heap.Klass;
import org.jvm.rtda.heap.classmember.Method;
import org.jvm.rtda.thread.*;

/**
 * @author 海燕
 * @date 2023/2/26
 */
public class NativeConstructorAccessorImplNativeMethod extends NativeMethodRegister {

    public static void init() throws NoSuchMethodException {
        register("sun/reflect/NativeConstructorAccessorImpl", "newInstance0", "(Ljava/lang/reflect/Constructor;[Ljava/lang/Object;)Ljava/lang/Object;", NativeConstructorAccessorImplNativeMethod.class.getDeclaredMethod("newInstance0", Frame.class));
    }

    public static void newInstance0(Frame frame) {
        LocalVars vars = frame.getLocalVars();
        Object constructorObj = vars.getRef(0);
        Object argArrObj = vars.getRef(1);
        Method constructor = getMethod(constructorObj, true);
        Klass klass = constructor.getKlass();
        //执行类初始化
        InstructionUtil.initClass(frame.getThread(), klass);
        Object obj = klass.newObject();

        OperandStack stack = frame.getOperandStack();
        stack.pushRef(obj);

        OperandStack tempStack = null;
        if (constructor.getArgSlotCount() > 0) {
            tempStack = new OperandStack(constructor.getArgSlotCount());
            if (!constructor.isStatic()) {
                tempStack.pushRef(obj);
            }
        }
        Frame tempFrame = NativeMethodUtil.newShimFrame(frame.getThread(), tempStack);
        InstructionUtil.invokeMethod(tempFrame, constructor);
    }

    private static Method getMethod(Object methodObj, boolean isConstructor) {
        java.lang.Object extra = methodObj.getExtra();
        if (extra != null) {
            return (Method) extra;
        }

        if (isConstructor) {
            return (Method) methodObj.getRefVar("root", "Ljava/lang/reflect/Constructor;").getExtra();
        } else {
            return (Method) methodObj.getRefVar("root", "Ljava/lang/reflect/Method;").getExtra();
        }
    }

}
